#include "stdlib.h"
#include "string.h"
#include <time.h>
#include <math.h>
#include "dvc.h"
#include "dvc_cmd_frame.h"
#include "dvc_log.h"

#define DVC_DEBUG 1

#if DVC_DEBUG
#include "stdio.h"
#define log_write printf
#else
#define log_write(x)
#endif

typedef struct dvc_bat_capacity_item
{
    uint16_t voltage; /* 在多少电压内 单位: mV */
    uint8_t capacity; /* 理论占比容量 单位: % */
} dvc_bat_capacity_item_t;
typedef struct dvc_bat_type_capacity
{
    dvc_bat_capacity_item_t low; /* 低电量范围 */
    dvc_bat_capacity_item_t mid; /* 中电量范围 */
    dvc_bat_capacity_item_t hig; /* 高电量范围 */
} dvc_bat_type_capacity_t;

// static const dvc_bat_type_capacity_t dvc_bat_type_capacity[BAT_TYPE_UNKNOWN] = {
//     /* 锂电池 */
//     {
//         .low = {.voltage = 3700, .capacity = 15}, /* 3.6-3.7   : 15% */
//         .mid = {.voltage = 4150, .capacity = 80}, /* 3.7-4.15  : 80% */
//         .hig = {.voltage = 4220, .capacity = 5},  /* 4.15-4.22  : 5% */
//     },
//     /* 磷酸铁锂 */
//     {
//         .low = {.voltage = 3200, .capacity = 15}, /* 2.8-3.2  :  20% */
//         .mid = {.voltage = 3300, .capacity = 80}, /* 3.2-3.3  :  80% */
//         .hig = {.voltage = 3600, .capacity = 5},  /* 3.3-3.6  :  5% */
//     },
// };

void dvc_init(dvc_t dvc, dvc_ops_t *ops, dvc_user_cfg_t *cfg)
{
    if (!dvc || !ops)
        return;
    memset(dvc, 0, sizeof(dvc_s));
    dvc->push_interval = 1000;
    dvc->ops = ops;
    dvc->retry_count = 3;
#if defined(DVC_ENABLE_LOG) || defined(DVC_ENABLE_EVENT_LOG)
    if (ops->get_logs)
        ops->get_logs(dvc);
#endif
    /* 获取用户/默认配置 */
    if (!cfg)
        dvc_read_user_config(dvc);
    else
        dvc->user_cfg = *cfg;
    /* 写入配置到AFE芯片 */
    dvc_config_init_default(dvc);
    /* 给默认值 */
    dvc->coulomb_counter.bat_rmA = dvc->coulomb_counter.bat_mA;
    /* 从flash中加载对应的历史值 */
    dvc_hitstory_restore(dvc);
}

dvc_t dvc_create(dvc_ops_t *ops, dvc_user_cfg_t *cfg)
{
    if (!ops)
    {
        log_write("Invalid parameter\n");
        return NULL;
    }
    dvc_t dvc = malloc(sizeof(dvc_s));
    if (!dvc)
    {
        log_write("Failed to malloc dvc object\n");
        return dvc;
    }
    dvc_init(dvc, ops, cfg);
    return dvc;
}

uint8_t dvc_reset(dvc_t dvc)
{
    if (!dvc || !dvc->ops || !dvc->ops->wakup)
        return 1;
    uint8_t data = 0xFF;
    dvc_frame_write(dvc, dvc_cmd_sleep, &data, 1);
    if (dvc->ops->delay_ms)
        dvc->ops->delay_ms(50);

    dvc->ops->wakup(dvc->ops->user_data);

    if (dvc->ops->delay_ms)
        dvc->ops->delay_ms(50);

#ifdef DVC_ENABLE_EVENT_LOG
    dvc_log_event_t event_log = {
        .timestamp = dvc->tick,
        .event = DVC_EVENT_TYPE_RESET,
        .flag = DVC_EVENT_FLAG_USER,
        .state = 0,
    };
    dvc_log_event_push(dvc, &event_log);
#endif
    dvc_read_user_config(dvc);

    return dvc_config_init_default(dvc);
}

void dvc_alert(dvc_t dvc)
{
    if (dvc)
    {
        dvc->alert = 1;
        dvc->io_alert = 1;
    }
}

void dvc_chg(dvc_t dvc, uint8_t en, uint8_t flag)
{
    if (!dvc)
        return;
    dvc->w_cfg.cfg0.chg_en = en > 0;

#ifdef DVC_ENABLE_EVENT_LOG
    // 如果chg_en状态发生变化，记录事件日志
    if (dvc->w_cfg.cfg0.chg_en != dvc->cfg.cfg0.chg_en)
    {
        dvc_log_event_t event_log = {
            .timestamp = dvc->tick,
            .event = DVC_EVENT_TYPE_CHG,
            .flag = flag,
            .state = dvc->w_cfg.cfg0.chg_en,
        };
        // 将事件日志推入日志队列
        dvc_log_event_push(dvc, &event_log);
    }
#endif
}

void dvc_dsg(dvc_t dvc, uint8_t en, uint8_t flag)
{
    if (!dvc)
        return;
    dvc->w_cfg.cfg0.dsg_en = en > 0;

#ifdef DVC_ENABLE_EVENT_LOG
    // 如果dsg_en状态发生变化，记录事件日志
    if (dvc->w_cfg.cfg0.dsg_en != dvc->cfg.cfg0.dsg_en)
    {
        dvc_log_event_t event_log = {
            .timestamp = dvc->tick,
            .event = DVC_EVENT_TYPE_DSG,
            .flag = flag,
            .state = dvc->w_cfg.cfg0.dsg_en,
        };
        // 将事件日志推入日志队列
        dvc_log_event_push(dvc, &event_log);
    }
#endif
}

void dvc_aes(dvc_t dvc, uint8_t en, uint8_t flag)
{
    if (!dvc)
        return;
    dvc->aes = en > 0;
    dvc->push = 1;
    dvc->push_tick += dvc->push_interval;
    dvc->aes_tick = dvc->tick;
    if (flag == DVC_EVENT_FLAG_USER)
        dvc->aes_user = en;
    if (dvc->ops->set_aes)
        dvc->ops->set_aes(dvc->ops->user_data, dvc->aes);
#ifdef DVC_ENABLE_EVENT_LOG
    dvc_log_event_t event_log = {
        .timestamp = dvc->tick,
        .event = DVC_EVENT_TYPE_AE,
        .flag = flag,
        .state = en,
    };
    dvc_log_event_push(dvc, &event_log);
#endif
}

/* 校准 */
void dvc_calib(dvc_t dvc, float v, float c)
{
    if (!dvc)
        return;
    dvc->calib.voltage = v;
    dvc->calib.current = c;
}

void dvc_tick(dvc_t dvc, uint16_t tick)
{
    if (!dvc)
        return;
    dvc->tick += tick;
    dvc->push_tick += tick;
    if (dvc->tick % 256 < tick)
        dvc->tick_flag |= dvc_tick_flag_256ms;
    if (dvc->tick % 1000 < tick)
    {
        dvc->tick_flag |= dvc_tick_flag_1s;
        dvc->timestamp++;
    }
    if (dvc->tick % 2000 < tick)
        dvc->tick_flag |= dvc_tick_flag_2s;
    if (dvc->tick % 4000 < tick)
        dvc->tick_flag |= dvc_tick_flag_4s;
    if (dvc->tick % 8000 < tick)
        dvc->tick_flag |= dvc_tick_flag_8s;
    if (dvc->tick % 16000 < tick)
        dvc->tick_flag |= dvc_tick_flag_16s;
    if (dvc->tick % 32000 < tick)
        dvc->tick_flag |= dvc_tick_flag_32s;
    if (dvc->tick % 64000 < tick)
        dvc->tick_flag |= dvc_tick_flag_64s;
}

void dvc_monitor(dvc_t dvc)
{
    if (!dvc)
        return;

    uint8_t tf = dvc->tick_flag;
    uint8_t tmask = (1 << dvc->cfg.cfg0.vs_pt);

    if (tf & tmask)
    {
        dvc->tick_flag &= ~tmask;
        dvc->read_cv = 1;   /* 读取电压电流 */
        dvc->read_c = 1;    /* 运算库仑计信息 */
        dvc->read_bat = 1;  /* 读取电池电压信息 */
        dvc->read_temp = 1; /* 读取温度信息 */
    }

#ifdef DVC_ENABLE_EVENT_LOG
    if (dvc->io_alert)
    {
        dvc->io_alert = 0;
        dvc_log_event_t event_log = {
            .timestamp = dvc->timestamp,
            .event = DVC_EVENT_TYPE_IO_ALTER,
            .flag = DVC_EVENT_FLAG_AFE,
            .state = 1,
        };
        dvc_log_event_push(dvc, &event_log);
    }
#endif

    if (dvc->alert)
    {
        /* 刷新标志位 */
        dvc_get_status_current_voltage(dvc);

        if (dvc->status.status0.ov) /* 过压 */
        {
            if (dvc->tick >= dvc->ov_tick)
            {
                uint32_t max = (dvc->user_cfg.afe.covt + 546) * 586 / 100; /* 0.586V/LSB */
                uint8_t clear = 1;
                for (uint8_t i = 0; i < dvc->bat_num; i++)
                {
                    if (dvc->bat_vol[i] > max)
                    {
                        clear = 0;
                        break;
                    }
                }
                if (clear)
                    dvc->status.status0.ov = 0;
            }
        }

        if (dvc->status.status0.uv) /* 欠压 */
        {
            if (!dvc->low_power)
            {
                dvc->low_power = 1;
                dvc->ops->low_power(dvc->ops->user_data, DVC_LOW_POWER_TYPE_ENABLE);
            }

            if (dvc->tick >= dvc->uv_tick)
            {
                uint32_t min = (dvc->user_cfg.afe.cuvt + 324) * 586 / 100; /* 0.586V/LSB */
                uint8_t clear = 1;
                for (uint8_t i = 0; i < dvc->bat_num; i++)
                {
                    if (dvc->bat_vol[i] < min)
                    {
                        clear = 0;
                        break;
                    }
                }
                if (clear)
                {
                    dvc->status.status0.uv = 0;
                    dvc->low_power = 0;
                    dvc->ops->low_power(dvc->ops->user_data, DVC_LOW_POWER_TYPE_DISABLE);
                }
            }
        }

        if (dvc->status.status0.ocd || dvc->status.status0.occ) /* 充放电过流 */
        {
            if (dvc->tick >= dvc->ccd_tick)
            {
                dvc->status.status0.ocd = 0;
                dvc->status.status0.occ = 0;
            }
        }

        if (dvc->status.status0.scd) /* 放电短路 */
        {
            if (dvc->tick >= dvc->scd_tick)
                dvc->status.status0.scd = 0;
        }

        uint8_t clear = 1;
        dvc_reg_status0_t status = dvc->status.status0;
        if (status.ocd || status.scd || status.uv || status.ov || status.occ || status.cs_st || status.vs_st) /* 警报还在 */
        {
            clear = 0;
            /* 开启了并联模式 && ((充电过流 && 电池没有超压) || (放电过流 && 电池没有欠压))  */
            if (dvc->parallel_mode && ((status.occ && !status.ov) || (status.ocd && !status.uv)))
            {
                clear = 1;
            }
        }

        /* 待做事项:
            1. 每次触发警报时，记录时间, 等待用户处理 / 用户超时不处理则自动恢复
         */
        if (clear) /* 警报已清除 */
        {
            dvc_clear_alert(dvc, DVC_EVENT_FLAG_AFE);
            dvc->alert = 0;
            printf("清除警报\r\n");
        }
    }

    if (dvc->check_reg)
    {
        dvc->check_reg = 0;
        if (dvc_config_check(dvc))
            dvc_config_commit(dvc);
    }

    if (dvc->read_bat)
    {
        dvc->read_bat = 0;
        if (dvc_get_bat_voltage(dvc))
            dvc->read_bat = 1;
    }

    if (dvc->read_cv)
    {
        dvc->read_cv = 0;
        if (dvc_get_status_current_voltage(dvc)) /* 读取失败则下次循环重试 */
            dvc->read_cv = 1;
    }

    if (dvc->read_temp)
    {
        dvc->read_temp = 0;
        if (dvc_get_temp(dvc))
            dvc->read_temp = 1;
    }

    if (dvc->read_c) /*  dvc_cs_vs_pt 执行一次 */
    {
        static const float pt2f[] = {0.256, 1, 2, 4, 8, 16, 32, 64};
        static const uint8_t pt2c[] = {4, 1, 1, 1, 1, 1, 1, 1};
        dvc->read_c = 0;
        /* 👇👇👇👇👇👇 待办项: 时间需要根据轮询标志位确定 👇👇👇👇👇 */
        dvc->coulomb_count++;                                /* 计数器+1 */
        float mA = dvc->current * pt2f[dvc->cfg.cfg0.vs_pt]; /* 累计 dvc_cs_vs_pt 内电流使用 */
        float mW = dvc->power * pt2f[dvc->cfg.cfg0.vs_pt];

        /* 1秒内累加 */
        dvc->coulomb_counter.sec.mA += mA; /* 电流累计 */
        dvc->coulomb_counter.sec.mW += mW; /* 功率累计 */

        /* 👇👇👇👇👇👇 待办项: 时间需要根据轮询标志位确定 👇👇👇👇👇 */
        /* 每秒清算一次*/
        if (dvc->coulomb_count >= pt2c[dvc->cfg.cfg0.vs_pt])
        {
            dvc->coulomb_count = 0;
            time_t timestamp = dvc->timestamp;
            struct tm t = {0};
            time(&timestamp);
            localtime_r(&timestamp, &t);
            dvc->timestamp = timestamp;
            /* 库仑计累计 和 剩余时间计算 */
            float current = fabsf(dvc->current);

            /* 累计 改成 1秒执行一次 */
            dvc->coulomb_counter.bat_rmA += (dvc->coulomb_counter.sec.mA * 1000) /* mA ->uA */; /* 电池容量累计 */
            if (dvc->coulomb_counter.bat_rmA < 0.000001f)
                dvc->coulomb_counter.bat_rmA = 0;

            /* 计算的容量超过设定容量  || 充电时, 电池电压 >= 总电压 99%  修正剩余容量 */
            if (dvc->coulomb_counter.bat_rmA > dvc->coulomb_counter.bat_mA || (dvc->current > 1e-6f && dvc->voltage >= (dvc->bat_max_voltage * dvc->bat_num) * 0.99))
                dvc->coulomb_counter.bat_rmA = dvc->coulomb_counter.bat_mA;

            if (dvc->current > 0.0f) /* 充电 */
            {
                /* 总累加 */
                dvc->coulomb_counter.sum.mA += dvc->coulomb_counter.sec.mA;
                dvc->coulomb_counter.sum.mW += dvc->coulomb_counter.sec.mW;
                /* 今日充电累计 */
                dvc->coulomb_counter.chg.mA += dvc->coulomb_counter.sec.mA;
                dvc->coulomb_counter.chg.mW += dvc->coulomb_counter.sec.mW;
                if (dvc->coulomb_counter.bat_mA >= 0.0)
                {
                    if (current > 1e-6f)
                        dvc->coulomb_counter.bat_rtime = (dvc->coulomb_counter.bat_mA - dvc->coulomb_counter.bat_rmA) / current;
                    else
                        dvc->coulomb_counter.bat_rtime = 0xFFFFFFFF;
                }
            }
            else /* 放电 */
            {
                dvc->coulomb_counter.dsg.mA += dvc->coulomb_counter.sec.mA;
                dvc->coulomb_counter.dsg.mW += dvc->coulomb_counter.sec.mW;
                if (current > 1e-6f)
                {
                    dvc->coulomb_counter.bat_rtime = dvc->coulomb_counter.bat_rmA / current;
                }
                else
                    dvc->coulomb_counter.bat_rtime = 0xFFFFFFFF;
            }

#ifdef DVC_ENABLE_LOG
            {
                // printf("d:%d h:%d m:%d s:%d\r\n", t.tm_yday, t.tm_hour, t.tm_min, t.tm_sec);
                dvc_log_record_sec(dvc);
                if (t.tm_min != dvc->log.time_min) /* 1min */
                {
                    // printf("update min %d->%d\r\n", dvc->log.time_min, t.tm_min);
                    dvc->log.time_min = t.tm_min;
                    dvc_log_record_minc(dvc);
                    if (t.tm_hour != dvc->log.time_hour)
                    {
                        // printf("update hour %d->%d\r\n", dvc->log.time_hour, t.tm_hour);
                        dvc->log.time_hour = t.tm_hour;
                        dvc_log_record_hour(dvc);
                    }
                }
            }
#endif
            dvc->coulomb_counter.sec.mA = 0;
            dvc->coulomb_counter.sec.mW = 0;

            if (t.tm_yday - dvc->last_day > 1) /* NTP时间同步导致的日期变更 */
            {
                log_write("last:%ld cur:%d timestamp:%lu only sync\r\n", dvc->last_day, t.tm_yday, dvc->timestamp);
                dvc->last_day = t.tm_yday;
            }

            if (t.tm_yday != dvc->last_day) /* 每日清零 */
            {
                dvc->last_day = t.tm_yday;
#ifdef DVC_ENABLE_LOG
                dvc_log_record_minc(dvc);
                dvc_log_record_hour(dvc);
                dvc_log_record_years(dvc, NULL); /* 记录一天均值 */
                dvc->log.sec_w = 0;
                dvc->log.min_w = 0;
                dvc->log.hour_w = 0;
#endif
                dvc->coulomb_counter.chg.mA = 0;
                dvc->coulomb_counter.chg.mW = 0;
                dvc->coulomb_counter.dsg.mA = 0;
                dvc->coulomb_counter.dsg.mW = 0;
                if (dvc->coulomb_counter.bat_mA > 0)
                {
                    uint16_t cycle_count = 0;
                    cycle_count = dvc->coulomb_counter.sum.mA / dvc->coulomb_counter.bat_mA;

                    // 衰减系数 磷酸铁锂大单体 衰减系数为: (100-82.5) / 3500 = 0.005f;
                    static const float decay_coefficient[BAT_TYPE_UNKNOWN + 1] = {0.05f, 0.005f, 0.1f};
                    float k = decay_coefficient[BAT_TYPE_UNKNOWN];

                    // 指数模型计算容量剩余百分比
                    dvc->coulomb_counter.bat_health = expf(-k * cycle_count);
                }
            }
        }
    }

    /*总线电流电压有变化 */
    if (dvc->change & dvc_data_current_change)
    {
        dvc->change &= ~dvc_data_current_change;
        dvc->push = 1;
    }
    /* 电池电压有变化 */
    if (dvc->change & dvc_data_voltage_change)
    {
        dvc->change &= ~dvc_data_voltage_change;
        dvc->push = 1;
    }
    /* 内外部温度有变化 */
    if (dvc->change & dvc_data_temp_change)
    {
        dvc->change &= ~dvc_data_temp_change;
        dvc->push = 1;
    }

    if (dvc->push) /* 数据已刷新 */
    {
        /* 到了数据上报时间 */
        if (dvc->push_tick >= dvc->push_interval)
        {
            dvc->push = 0;
            dvc->push_tick %= dvc->push_interval;
            /* 数据上报 */
            if (dvc->ops && dvc->ops->new_data)
                dvc->ops->new_data(dvc);
        }
    }
}